using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 导航辅助组件
    /// 可实现多段复杂寻路
    /// </summary>
    public class LgNpcNavAssistantComponent : LogicBaseEntityComponent
    {
        private LevelEntity _entity;
        private int _restartNavFrame;
        private bool _isEnabled;
        private Queue<LogicLevelMoveParam> _navPosQueue = new Queue<LogicLevelMoveParam>();
        private bool _needAdjustPos;
        /// <summary>
        /// 是否自我管理，自我管理表示不和其他组件搭配，纯寻路，且会被纪录到关卡缓存中，有纪录存在时，不允许存档
        /// 自我管理的寻路辅助组件被认为是普通寻路，非普通寻路还包含怪物巡逻，循环表演等，要么未使用该组件，要么需和其他组件搭配使用
        /// </summary>
        private bool _manageSelf;
        #region 直接移动模式相关字段
        /// <summary>
        /// 导航时是否依照recast navmesh网格，如果不按网格走则表示是直接移动的模式
        /// </summary>
        private bool _alongRecastMesh;
        /// <summary>
        /// 直接移动模式（不走recast navmesh）开始帧
        /// </summary>
        private int _directMoveElapsedFrame = -1;
        /// <summary>
        /// 直接移动模式开始时的位置
        /// </summary>
        private Vector3Logic _directMoveStartPos;
        /// <summary>
        /// 直接移动的目标点（不走recast navmesh）
        /// </summary>
        private LogicLevelMoveParam _directMoveTarget;
        /// <summary>
        /// 是否激活（专为非网格模式设置，网格模式是否激活通过LogicNavigator实现）
        /// </summary>
        private bool _isDirectMoveActive;
        private Vector3Logic _directMoveDir;
        /// <summary>
        /// 寻路结束后是否触发【寻路结束】服务触发器
        /// </summary>
        private bool _triggerNavEndService;
        #endregion

        public bool needWaitHero { get; private set; }
        /// <summary>
        /// 是否正在寻路（注意如果为否，未必就到达了终点，因为可能会有多个路径，如果想知道是否到达了终点，调用navIsComplete）
        /// </summary>
        public bool isNavigating => (_entity != null && _entity.navigator.isNavigating) || _directMoveElapsedFrame != -1;
        /// <summary>
        /// 寻路是否完全结束
        /// </summary>
        public bool navIsComplete => _navPosQueue.Count == 0 && !isNavigating;
        public Vector3Int finalDestination { get; private set; }

        public override uint MaxStore => 2;
        public bool combinedWithOtherComponent => !_manageSelf;

        public override void Awake(BaseEntity entity)
        {
            this._entity = entity as LevelEntity;
            _isEnabled = true;
        }

        /// <summary>
        /// 开始寻路
        /// </summary>
        /// <param name="posList">寻路移动信息集合，移动信息里包括了目标点，速度倍率等</param>
        /// <param name="needWaitHero">是否检查英雄距离并等待英雄（会消耗更多的性能）</param>
        /// <param name="needAdjustPos">是否校验posList里的目标点，如果数据来自配置请设置为true</param>
        /// <param name="alongRecastMesh">是否由Recast寻路底层驱动，如果否则进行支线寻路（物理寻路区域有效）</param>
        /// <param name="manageSelf">是否自我管理，如果是，为单纯寻路，会自动将实体交互类型修改为None，且结束后会触发寻路结束服务，并自行移除，否则为复杂逻辑，需和其他组件配合，由其他组件来执行相关逻辑（如怪物巡逻）</param>
        public void TryStartNav(LogicLevelMoveParam[] posList, bool needWaitHero, bool needAdjustPos, bool alongRecastMesh = true, bool manageSelf = false)
        {
            if (!navIsComplete)
            {
                EndNav();
            }
            finalDestination = posList[posList.Length - 1].destination;
            _navPosQueue.Clear();
            for (int i = 0; i < posList.Length; i++)
            {
                _navPosQueue.Enqueue(posList[i]);
            }
            this.needWaitHero = needWaitHero;
            _needAdjustPos = needAdjustPos;
            _alongRecastMesh = alongRecastMesh;
            NavToNextPos();
            _manageSelf = manageSelf;
            if (manageSelf)
            {
                _triggerNavEndService = true;
                _entity.region.RecordNavEntity(_entity);
                //改变交互类型
                _entity.SetInteractType(0, true);
            }
        }

        public void EndNav()
        {
            EndNav(_entity.position);
        }

        public void EndNav(Vector3Logic stopPos)
        {
            _navPosQueue?.Clear();
            _restartNavFrame = -1;
            StopNavigation(stopPos);
        }

        private void NavToNextPos()
        {
            if (_navPosQueue.Count > 0)
            {
                LogicLevelMoveParam moveParam = _navPosQueue.Dequeue();
                StartNavigation(moveParam);
            }
        }

        public override void LogicOnUpdate()
        {
            if (_restartNavFrame != -1 && _entity.region.level.levelFrame >= _restartNavFrame)
            {
                SetNavActive(true);
                _restartNavFrame = -1;
            }
            else
            {
                if (!_alongRecastMesh && _isDirectMoveActive && _directMoveElapsedFrame != -1) //直线移动模式，不依赖网格
                {
                    _directMoveElapsedFrame++;
                    float realTimeSpeed = _entity.moveSpeed * _directMoveTarget.speedRatio;
                    float speedPerFrame = realTimeSpeed / LgLevelConst.FrameRate;
                    Vector3Logic curPos = _directMoveStartPos + _directMoveDir * _directMoveElapsedFrame * speedPerFrame;
                    Vector3Logic curPosToEnd = (Vector3Logic)_directMoveTarget.destination - curPos;
                    float dot = curPosToEnd.x * _directMoveDir.x + curPosToEnd.z * _directMoveDir.z;
                    if (dot > 0)
                    {
                        //不依赖网格，直接移动位置
                        _entity.UpdateMove(curPos, realTimeSpeed / _entity.defaultMoveSpeed);
                    }
                    else //如果当前算出来的位置在终点后面，则直接停止
                    {
                        //不依赖网格，直接移动位置
                        _entity.UpdateMove(_directMoveTarget.destination, realTimeSpeed / _entity.defaultMoveSpeed);
                        StopNavigation(_entity.position);
                    }
                }
                if (!isNavigating && _navPosQueue.Count > 0)
                {
                    NavToNextPos();
                }
            }
            if (needWaitHero)
            {
                if (IsHeroTooFar())
                {
                    SetNavEnabled(false, 0);
                }
                else
                {
                    SetNavEnabled(true, LgLevelConst.NpcNavRestartTime);
                }
            }
            if (_manageSelf && navIsComplete)
            {
                StopAndDestroy(true, _entity.position);
            }
        }

        public void StopAndDestroy()
        {
            StopAndDestroy(false, _entity.position);
        }

        public void StopAndDestroy(bool triggerService, Vector3Logic stopPos)
        {
            _triggerNavEndService = triggerService;
            if (!navIsComplete)
            {
                EndNav(stopPos);
            }
            _entity.RemoveComponent<LgNpcNavAssistantComponent>();
        }

        public bool IsHeroTooFar()
        {
            LevelHeroEntity heroEntity = LgLevelEntityUtil.GetClosestHero(_entity);
            LevelPlayer player = heroEntity.player;
            return (player.entity.position - _entity.position).sqrMagnitude > LgLevelConst.MaxSqrDistanceFromHeroWhenNpcNav;
        }

        public override void OnRelease()
        {
#if UNITY_EDITOR
            //保险，实际操作应在移除Component前手动停止
            if (!navIsComplete)
            {
                LogicLog.LogError("LgNpcNavAssistantComponent组件还未停止，请先停止再移除或销毁");
                EndNav();
            }
#endif
            _restartNavFrame = -1;
            _isEnabled = false;
            _alongRecastMesh = true;
            _isDirectMoveActive = false;
            _directMoveTarget = default;
            _directMoveStartPos = default;
            finalDestination = default;
            _directMoveElapsedFrame = -1;
            if (_manageSelf)
            {
                _manageSelf = false;
                _entity.region.RemoveNavEntityRecord(_entity);
                _entity.RecoverInteractType(true);
            }
            if (_triggerNavEndService)
            {
                _triggerNavEndService = false;
                _entity.TryTriggerService(null, ServiceTriggerType.EntityStopNavigation);
            }
            _entity = null;
            _restartNavFrame = 0;
            _needAdjustPos = false;
            _alongRecastMesh = false;
        }

        /// <summary>
        /// 与SetNavActive相比，可由外部调用，可设置启动延迟，可兼容反复调用
        /// </summary>
        /// <param name="isEnabled"></param>
        /// <param name="enableSecDelay"></param>
        public void SetNavEnabled(bool isEnabled, int enableSecDelay = 0)
        {
            if (_isEnabled == isEnabled)
            {
                return;
            }
            _isEnabled = isEnabled;
            _restartNavFrame = -1;
            if (!isEnabled)
            {
                SetNavActive(false);
            }
            else
            {
                if (enableSecDelay > 0)
                {
                    _restartNavFrame = _entity.region.level.levelFrame + enableSecDelay * LgLevelConst.FrameRate;
                }
                else
                {
                    SetNavActive(true);
                }
            }
        }

        #region 两种不同移动模式的整合api
        private void StartNavigation(LogicLevelMoveParam moveParam)
        {
            if (_alongRecastMesh)
            {
                _entity.StartNavigation(moveParam.destination, _needAdjustPos, (int)Math.Round(_entity.moveSpeed * moveParam.speedRatio));
            }
            else
            {
                _directMoveElapsedFrame = 0;
                _directMoveStartPos = _entity.position;
                _directMoveTarget = moveParam;
                _isDirectMoveActive = true;
                Vector3Logic startToEnd = (Vector3Logic)_directMoveTarget.destination - _directMoveStartPos;
                _directMoveDir = startToEnd.normalized;
            }
        }

        /// <summary>
        /// 与SetNavEnabled相比功能更单一，SetNavEnabled会调用该接口
        /// </summary>
        /// <param name="value"></param>
        private void SetNavActive(bool value)
        {
            if (_alongRecastMesh)
            {
                _entity.navigator.SetActive(value);
            }
            else
            {
                _isDirectMoveActive = value;
            }
        }

        private void StopNavigation(Vector3Logic stopPos)
        {
            if (!isNavigating)
            {
                return;
            }
            if (_alongRecastMesh)
            {
                _entity.StopNavigation(true, stopPos);
            }
            else
            {
                _directMoveElapsedFrame = -1;
                _directMoveStartPos = Vector3Logic.zero;
                _directMoveTarget = default;
                _isDirectMoveActive = false;
                _entity.UpdateMove(stopPos, 1);
            }
        }
        #endregion
    }
}
